package net.pws.common.persistence.hibernate3;

import java.util.Collection;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

/**
 * Example������ѡ��������Ŀ����ѡ��ָ������������ɲ�ѯ����
 */
public interface PropertySelector {
    /**
     * ���е����Ծ�ɹ��ɲ�ѯ����
     */
    public static final PropertySelector ALL = new AllPropertySelector();
    
    /**
     * ���з�null���Կɹ��ɲ�ѯ����
     */
    public static final PropertySelector NOT_NULL = new NotNullPropertySelector();
    
    /**
     * ���з�null���0�����Կɹ��ɲ�ѯ����
     */
    public static final PropertySelector NOT_NULL_OR_ZERO = new NotNullOrZeroNumberPropertySelector();
    
    /**
     * ���з�null���0�����Կɹ��ɲ�ѯ����
     */
    public static final PropertySelector NOT_NULL_OR_EMPTY_STRING = new NotNullOrEmptyStringPropertySelector();
    
    /**
     * ���з�java.util.Collection���͵����Կɹ��ɲ�ѯ����
     */
    public static final PropertySelector NOT_COLLECTION = new NotCollectionPropertySelector();
    
    /**
     * ���з�java.util.Map���͵����Կɹ��ɲ�ѯ����
     */
    public static final PropertySelector NOT_MAP = new NotMapPropertySelector();
    
    /**
     * 
     *
     */
    public static abstract class AbstractPropertySelector implements
                                                         PropertySelector {
        
        public PropertySelector and(final PropertySelector propertySelector) {
            final AbstractPropertySelector ref = this;
            return new AbstractPropertySelector() {
                public boolean include(String propertyName,
                                       Class propertyClazz,
                                       Object propertyValue) {
                    return ref.include(propertyName,
                                       propertyClazz,
                                       propertyValue) && propertySelector.include(propertyName,
                                                                                  propertyClazz,
                                                                                  propertyValue);
                }
            };
        }
        
        public PropertySelector or(final PropertySelector propertySelector) {
            final AbstractPropertySelector ref = this;
            return new AbstractPropertySelector() {
                public boolean include(String propertyName,
                                       Class propertyClazz,
                                       Object propertyValue) {
                    return ref.include(propertyName,
                                       propertyClazz,
                                       propertyValue) || propertySelector.include(propertyName,
                                                                                  propertyClazz,
                                                                                  propertyValue);
                }
            };
        }
    }
    
    /**
     * 
     *
     */
    public static final class AllPropertySelector extends
                                                 AbstractPropertySelector {
        public boolean include(String propertyName,
                               Class propertyClazz,
                               Object object) {
            return true;
        }
    }
    
    /**
     *
     */
    public static final class NotNullPropertySelector extends
                                                     AbstractPropertySelector {
        public boolean include(String propertyName,
                               Class propertyClazz,
                               Object object) {
            return object != null;
        }
    }
    
    /**
     *
     */
    public static final class NotNullOrZeroNumberPropertySelector extends
                                                                 AbstractPropertySelector {
        public boolean include(String propertyName,
                               Class propertyClazz,
                               Object object) {
            return object != null && (!(object instanceof Number) || ((Number) object).longValue() != 0);
        }
    }
    
    /**
     *
     */
    public static final class NotNullOrEmptyStringPropertySelector extends
                                                                  AbstractPropertySelector {
        public boolean include(String propertyName,
                               Class propertyClazz,
                               Object object) {
            return object != null && (!(object instanceof String) || StringUtils.isNotEmpty((String) object));
        }
    }
    
    /**
     *
     */
    public static final class NotCollectionPropertySelector extends
                                                           AbstractPropertySelector {
        public boolean include(String propertyName,
                               Class propertyClazz,
                               Object object) {
            return !Collection.class.isAssignableFrom(propertyClazz);
        }
    }
    
    /**
     *
     */
    public static final class NotMapPropertySelector extends
                                                    AbstractPropertySelector {
        public boolean include(String propertyName,
                               Class propertyClazz,
                               Object object) {
            return !Map.class.isAssignableFrom(propertyClazz);
        }
    }
    
    /**
     * �ж�ָ���������Ƿ�Ϊ��Ч����
     * 
     * @param propertyName
     * @param propertyClazz
     * @param propertyValue
     * @return
     */
    public boolean include(String propertyName,
                           Class propertyClazz,
                           Object propertyValue);
    
    /**
     * ��ָ����PropertySelector�����߼�������
     * 
     * @param propertySelector
     * @return
     */
    public PropertySelector and(PropertySelector propertySelector);
    
    /**
     * ��ָ����PropertySelector�����߼�������
     * 
     * @param propertySelector
     * @return
     */
    public PropertySelector or(PropertySelector propertySelector);
}
